#include "mof_protocol.h"
#include "tcpclient.h"
#include "def_enum.h"
#include "my_aes.h"
#include "quiwidget.h"
#include <string.h>
#include <QDebug>

mof_protocol::mof_protocol(QObject *parent) : QObject(parent)
{
    connect(this, &mof_protocol::mofSignalLog, CommSignalSlot::Instance(), &CommSignalSlot::CommSlotLog);
    init_protocol();
    read_conf();
    memset(queue_para.data, 0, sizeof(queue_para.data));
    queue_para.offset = 0;
    time(&opt_time);
}

void mof_protocol::init_protocol()
{
    pro_para.login_status = 0;
    pro_para.link_status = 0;
    pro_para.protool_status = 0;
    pro_para.heart_interval = 10;
    pro_para.heart_time = 0;
    pro_para.link_port = 0;
    memset(&pro_para.link_server, 0, sizeof (pro_para.link_server));
    memset(&pro_para.link_tocken, 0, sizeof (pro_para.link_tocken));
    memset(&pro_para.link_plugin_id, 0, sizeof (pro_para.link_plugin_id));
    memset(&pro_para.conf, 0, sizeof(pro_para.conf));
}


mof_protocol* mof_protocol::Instance()
{
    static mof_protocol ptl;

    return &ptl;
}

void mof_protocol::read_conf()
{
    get_key_value_str(KEY_PIN, "04020B0309AD", pro_para.conf.pin_code, sizeof(pro_para.conf.pin_code));//PIN码固定12位
    get_key_value_str("SN", "FCEEE663E50A", pro_para.conf.sn_code, sizeof(pro_para.conf.sn_code));
    get_key_value_str(KEY_KEY, "0C650154B17C3046", pro_para.conf.protool_key, sizeof(pro_para.conf.protool_key));
    get_key_value_str(KEY_SERVER, DEF_SERVER_IP, pro_para.conf.login_server, sizeof(pro_para.conf.login_server));//服务器的域名或IP地址
    get_key_value_str(KEY_PORT, DEF_SERVER_PORT, pro_para.conf.login_port, sizeof(pro_para.conf.login_port));

    emit mofSignalLog(CommSignalSlot::logSTR, ">>", "config para:----");
    QString tmp;

    tmp = QString("%1:%2--%3").arg("pin_code").arg(pro_para.conf.pin_code).arg(strlen(pro_para.conf.pin_code));
    emit mofSignalLog(CommSignalSlot::logSTR, ">>", tmp);

    tmp = QString("%1:%2--%3").arg("sn_code").arg(pro_para.conf.sn_code).arg(strlen(pro_para.conf.sn_code));
    emit mofSignalLog(CommSignalSlot::logSTR, ">>", tmp);

    tmp = QString("%1:%2--%3").arg("protool_key").arg(pro_para.conf.protool_key).arg(strlen(pro_para.conf.protool_key));
    emit mofSignalLog(CommSignalSlot::logSTR, ">>", tmp);

    tmp = QString("%1:%2--%3").arg("login_server").arg(pro_para.conf.login_server).arg(strlen(pro_para.conf.login_server));
    emit mofSignalLog(CommSignalSlot::logSTR, ">>", tmp);

    tmp = QString("%1:%2--%3").arg("login_port").arg(pro_para.conf.login_port).arg(strlen(pro_para.conf.login_port));
    emit mofSignalLog(CommSignalSlot::logSTR, ">>", tmp);
}

int mof_protocol::get_key_value_str(const char *key, const char *default_str, char *ret_str, unsigned int ret_str_size)
{
    if (default_str == NULL) {
        printf("Not find Key=\"%s\" and no default_str to use.", key);
        return -1;
    }
    int len = strlen(default_str);
    len = ((unsigned int)len < (ret_str_size - 1) ? len : (ret_str_size - 1));
    strncpy(ret_str, default_str, len);
    ret_str[len] = '\0';

    return -1;
}

unsigned char mof_protocol::get_check_sum(unsigned char *pack, int pack_len)
{
    unsigned char check_sum =0;
    while(--pack_len>=0)
    {
        check_sum += *pack++;
    }
    return check_sum;
}

int mof_protocol::push(char *buff, int length)
{
    std::lock_guard<std::mutex> lock(_mutex);

    if((queue_para.offset + length) > 1024*2)
    {
        qDebug() << "over flow\n";
        return -1;
    }
    memcpy(queue_para.data + queue_para.offset, buff, length);
    queue_para.offset += length;

    return 0;
}

int mof_protocol::popup(PACKAGE_HEAD* phead, DATA_HEAD *dhead, char* optbuff, char *buff, short* seq)
{
    int i =0;

    std::lock_guard<std::mutex> lock(_mutex);

    if((int)(queue_para.offset) > (int)(sizeof(PACKAGE_HEAD)))
    {
        for(i = 0; i< queue_para.offset-2; i++)
        {
            *phead= *(PACKAGE_HEAD*)(queue_para.data+i);

            if((*phead).magic == DX_MAGIC_HEAD)
            {
                //printf("found head\n");
                if((int)(queue_para.offset-i-3)>=(int)(sizeof(DATA_HEAD)))
                {

                    *dhead = *(DATA_HEAD*)(queue_para.data+i+3);
                    (*dhead).length = (*dhead).length;

                    int tmp =0;

                    if((int)(queue_para.offset-i-3-sizeof(DATA_HEAD))>=(int)((*dhead).length+(*dhead).optLength+tmp))
                    {
                        if((*dhead).optLength>0)
                        {
                            memcpy(optbuff,queue_para.data+i+3+sizeof(DATA_HEAD),(*dhead).optLength);
                        }
                        if((*dhead).length>0)
                        {
                            *seq =*(short*)(queue_para.data+i+3+sizeof(DATA_HEAD)+(*dhead).optLength);
                            *seq = *seq;
                            memcpy(buff , queue_para.data+i+3+sizeof(DATA_HEAD)+(*dhead).optLength,(*dhead).length);
                        }
                        int tmplen = ((*dhead).length+(*dhead).optLength+tmp+i+3+sizeof(DATA_HEAD));
                        queue_para.offset -=tmplen;

                        char tmp [1024];
                        memcpy(tmp,queue_para.data+tmplen,queue_para.offset);
                        memcpy(queue_para.data,tmp,queue_para.offset);
                        return 0;
                    }
                    else
                    {
                        return -1;
                    }
                }
                else
                {
                    return -1;
                }
            }
        }
    }

    return -1;
}

int mof_protocol::mof_crypt(char *enc_s_buf, char *encbuf, int *Number, int *Total, int Len)
{
    int nBei = Len / AES_BLOCK_SIZE + 1;

    *Total = nBei * AES_BLOCK_SIZE;
    if (Len % 16 > 0)
        *Number = *Total - Len;
    else
        *Number = 16;
    memset(enc_s_buf, *Number, *Total);
    memcpy(enc_s_buf, encbuf, Len);

    return nBei;
}

int mof_protocol::aes_decrypt(char* enckey, char* encbuf, char* decbuf, int inlen, int* outlen)
{
    AES_KEY aes;
    char key[16]="";// = "12345678";
    char iv[16] = "";
    int nBei, nTotal, nNumber;

    if((!encbuf)||(!decbuf)) return -1;

    memcpy(key, enckey, 16);
    nBei = mof_crypt(enc_s_buf, encbuf, &nNumber, &nTotal, inlen);
    if (AES_set_decrypt_key((unsigned char*)key, 128, &aes) < 0)
    {
        fprintf(stderr, "Unable to set decryption key in AES error !!!!!\n");
        return -1;
    }

    AES_cbc_encrypt((unsigned char *)enc_s_buf, (unsigned char*)decbuf, nTotal, &aes, (unsigned char*)iv, AES_DECRYPT);
    nTotal -=16;
    nNumber=decbuf[nTotal-1];
    *outlen=nTotal-nNumber;

    return 0;
}

int mof_protocol::aes_encrypt(char* enckey, char* encbuf, char* decbuf, int inlen, int* outlen)
{
    AES_KEY aes;
    char key[16]="";// = "12345678";
    memcpy(key, enckey, 16);
    char iv[16] = "";

    int nBei, nTotal, nNumber;

    if((!encbuf)||(!decbuf)) return -1;

    nBei = mof_crypt(enc_s_buf, encbuf, &nNumber, &nTotal, inlen);
    if (AES_set_encrypt_key((unsigned char*)key, 128, &aes) < 0)
    {
        emit mofSignalLog(CommSignalSlot::logSTR, ">>", "Unable to set encryption key in AES error !!!!!\n");
        return -1;
    }

    AES_cbc_encrypt((unsigned char *)enc_s_buf, (unsigned char*)decbuf, nBei * 16, &aes, (unsigned char*)iv, AES_ENCRYPT);
    * outlen = nBei * 16;

    return 0;
}

int mof_protocol::mof_recv_parse(PACKAGE_HEAD phead, DATA_HEAD dhead, char *optbuff, char *buff, short seq)
{
    char out[1024], tmpA[1024];
    int i=0;
    int outlen;

    if(seq ==-1)//force logout
    {
        emit mofSignalLog(CommSignalSlot::logSTR, ">>", "net error reconnect\n");
        pro_para.protool_status = 1;
        return 0;
    }

    switch ((phead.headp&0x1f))
    {
        case force_logout:
            emit mofSignalLog(CommSignalSlot::logSTR, ">>", "force disconnect exit !!!!!\n");
            break;

        case heart_ack:
            emit mofSignalLog(CommSignalSlot::logSTR, ">>", "heart beep ack\n");
            time_t curtime;
            time(&curtime);
            pro_para.heart_time = curtime;
            break;

        case management_pack_ack:
        {
            emit mofSignalLog(CommSignalSlot::logSTR, "management_pack_ack:",QString::number(dhead.length));
            if((dhead.length>0))
            {
                int ret = aes_decrypt((char*)pro_para.conf.protool_key, buff, out, dhead.length, &outlen);
                if(ret !=0)
                {
                    emit mofSignalLog(CommSignalSlot::logSTR, ">>", "descrypt error\n");
                    break;
                }
            }

            break;
        }
        case management_pack_down:
        {
            emit mofSignalLog(CommSignalSlot::logSTR, ">>", "management_pack_down\n");

            if(dhead.length>0)
            {
                int ret = aes_decrypt((char*)pro_para.conf.protool_key, buff, out, dhead.length, &outlen);
                if(ret !=0)
                {
                    emit mofSignalLog(CommSignalSlot::logSTR, ">>", "descrypt error\n");
                    break;
                }

                data_device_mt_req *data=(data_device_mt_req*)(out + 2);
                data->length = data->length;
                QString tmp = QString("management_pack_down datatype %1,%2").arg(data->dataType).arg(data->length);
                emit mofSignalLog(CommSignalSlot::logSTR, ">>", tmp);

                short len = data->length;
                char* pData = (out+5);

                tmp = QString("len %1,outlen = %2,%3").arg(dhead.length).arg(outlen).arg(out[outlen-1]);
                emit mofSignalLog(CommSignalSlot::logSTR, ">>", tmp);

                memset(tmpA, 0, 1024);
                memcpy(tmpA, &dhead.length, 2);

                if(dhead.optLength)
                    memcpy(tmpA+2,optbuff,dhead.optLength);
                if(outlen>0)
                    memcpy(tmpA+2+dhead.optLength,out,outlen);

                u8 checks = get_check_sum((unsigned char *) tmpA, 2 + dhead.optLength + outlen);
                printf("checks = %x, %x\n",checks, dhead.checksum);

                if (checks != dhead.checksum)
                 {
                    emit mofSignalLog(CommSignalSlot::logSTR, ">>", "checksum err\n");
                    send_management_ack_data(checksum_err, 0, 0);
                }
                else
                {
                    int r;
                    memset(tmpA, 0, sizeof(tmpA));
                    switch (data->dataType)
                    {
                        case datatype_upgrade_cmd://下发升级指令
                            memcpy(tmpA, pData, data->length);
                            //r = gw_parse_upgrade_cmd(tmpA);
                            if (r==0)
                            {
                                send_management_ack_data(0, 0, 0); //(unsigned char *) response, responselen);
                                emit mofSignalLog(CommSignalSlot::logSTR, ">>", ">>>>>>>>>>>>>>upgrade_cmd ack.\n");
                            }
                            else
                            {
                                char msg[]="6.5.1 error";
                                emit mofSignalLog(CommSignalSlot::logSTR, ">>", "6.5.1 error\n");
                                send_management_ack_data(r, (unsigned char *) msg, strlen(msg));
                            }
                            break;

                        case datatype_upgrade_param://下发升级数据
                            memcpy(tmpA, pData, data->length);
                            //r = gw_parse_upgrade_param(tmpA);
                            if (r==0)
                            {
                                send_management_ack_data(0, 0, 0); //(unsigned char *) response, responselen);
                                emit mofSignalLog(CommSignalSlot::logSTR, ">>", ">>>>>>>>>>>>>>upgrade_param ack.\n");
                                //gw_parse_do_upgrade();
                            }
                            else {
                                char msg[]="6.5.2 error";
                                send_management_ack_data(r, (unsigned char *) msg, strlen(msg));
                            }
                            break;
                        default:
                            send_management_ack_data(0, 0, 0); //(unsigned char *) response, responselen);
                            break;
                    }
                }
            }

            break;
        }

        case bissness_pack_ack:
        {
            emit mofSignalLog(CommSignalSlot::logSTR, "bissness_pack_ack ",QString::number(dhead.length));
            if((dhead.length>0))
            {
                int ret = aes_decrypt((char*)pro_para.conf.protool_key, buff, out,dhead.length, &outlen);
                if(ret !=0)
                {
                    emit mofSignalLog(CommSignalSlot::logSTR, ">>", "descrypt error\n");
                    break;
                }
            }
            break;
        }

        case bissness_pack_down:
        {
            emit mofSignalLog(CommSignalSlot::logSTR, ">>", "bissness_pack_down\n");

            if(dhead.length>0)
            {
                int ret = aes_decrypt((char*)pro_para.conf.protool_key, buff, out, dhead.length, &outlen);
                if(ret != 0)
                {
                    emit mofSignalLog(CommSignalSlot::logSTR, ">>", "descrypt error\n");
                    break;
                }
                QByteArray tmp = QByteArray(out, outlen);
                QString log = QUIHelper::byteArrayToHexStr(tmp);
                emit mofSignalLog(CommSignalSlot::logDateTime, "decrypt:", log);



                char* pData = (out+2);
                short len = outlen - 2;
                pData[len]='\0';

                log = QString(pData);
                emit mofSignalLog(CommSignalSlot::logDateTime, "str_decrypt:", log);

                QString kk = QString("len %1,outlen = %2,%3\n").arg(dhead.length).arg(outlen).arg((unsigned char)out[outlen-1]);
                emit mofSignalLog(CommSignalSlot::logSTR, ">>", kk);

                memset(tmpA,0,1024);
                memcpy(tmpA, &dhead.length, 2);

                if(dhead.optLength)
                    memcpy(tmpA + 2, optbuff, dhead.optLength);
                if(outlen>0)
                    memcpy(tmpA + 2 + dhead.optLength, out, outlen);

                //printhex(checkkdata, 2+dhead.optLength+outlen, __func__);

                U8 checks = get_check_sum((unsigned char *) tmpA, 2 + dhead.optLength + outlen);
                printf("checks = %x, %x\n",checks,dhead.checksum);

                if (checks != dhead.checksum) {
                    send_business_ack_data(checksum_err, nullptr, 0);
                }
                else{
                    /*char msgadd[] = ",\"sequence\":123}\0";
                    memcpy(&pData[len-1], msgadd, strlen(msgadd));
                    len = len + strlen(msgadd) - 1;*/

                    dev_data_down(pData, len);

                    /*sleep(2);
                    char updataT[100] = "{\"sequence\":0,\"SongControlS\":2}";
                    int data_len = swapInt16(strlen(updataT));

                    send_dev_data_up(updataT, data_len);*/
                }
            }

            break;
        }

        case ack:
        {
            if(!pro_para.login_status)
            {
                short errerno = *(short*)optbuff;
                if(dhead.optLength > 0)
                {
                    QString tmp = QString("######## optlen %1, err code or radom [%2]\n").arg(dhead.optLength).arg(errerno);
                    emit mofSignalLog(CommSignalSlot::logSTR, ">>", tmp);
                }

                emit mofSignalLog(CommSignalSlot::logSTR, "login ack ===len ",QString::number(dhead.length));
                if(errerno == 0)
                {
                    int ret = aes_decrypt((char*)pro_para.conf.protool_key, buff, out, dhead.length, &outlen);
                    if(ret != 0)
                    {
                        emit mofSignalLog(CommSignalSlot::logSTR, ">>", "descrypt error\n");
                        break;
                    }
                    data_login_response* res = (data_login_response*)(out + PACKAGE_SEQ_LENGTH);
                    // session
                    memcpy(pro_para.link_tocken, res->token, 32);
                    // link IP
                    sprintf(pro_para.link_server,"%d.%d.%d.%d",res->ip[0],res->ip[1],res->ip[2],res->ip[3]);
                    // link port
                    pro_para.link_port = res->port;
                    // 插件ID
                    memcpy(pro_para.link_plugin_id, res->deviceId, 32);
                    pro_para.login_status = 1;

                    printf("login ack======ip:%d,%d,%d,%d,port:%d,pluginId %s\n",
                           res->ip[0],res->ip[1],res->ip[2],res->ip[3],res->port, pro_para.link_plugin_id);

                    QString tmp = QString("%1,%2,%3,%4,port:%5,pluginId %6\n")
                                  .arg(res->ip[0]).arg(res->ip[1]).arg(res->ip[2]).arg(res->ip[3])
                                  .arg(res->port).arg(pro_para.link_plugin_id);
                    emit mofSignalLog(CommSignalSlot::logSTR, "login ack======ip:", tmp);

                    emit mofSignalLog(CommSignalSlot::logSTR, "login ok tocken ,port \n", QString::number(pro_para.link_port));
                }
                else
                {
                    emit mofSignalLog(CommSignalSlot::logSTR, ">>", "login ack error\n");
                }
            }
            else
            {
                emit mofSignalLog(CommSignalSlot::logSTR, ">>", "link ack\n");
                short errerno = *(short*)optbuff;
                if (dhead.optLength>0)
                {
                    QString tmp = QString("######## optlen %1, err code or radom [%2]\n").arg(dhead.optLength).arg(errerno);
                    emit mofSignalLog(CommSignalSlot::logSTR, ">>", tmp);
                }
                if (errerno == 0)
                {
                    int ret = aes_decrypt((char*)pro_para.conf.protool_key, buff, out, dhead.length, &outlen);
                    if(ret != 0)
                    {
                        emit mofSignalLog(CommSignalSlot::logSTR, ">>", "descrypt error\n");
                        break;
                    }

                    data_link_response* res = (data_link_response*)(out + PACKAGE_SEQ_LENGTH);

                    pro_para.heart_interval = res->heartbeat;
                    if(pro_para.heart_interval < 5)
                        pro_para.heart_interval = 5;
                    emit mofSignalLog(CommSignalSlot::logSTR, "link ack heartbeep interval ", QString::number(res->heartbeat));

                    pro_para.link_status = 1;

                }
                else
                {
                    emit mofSignalLog(CommSignalSlot::logSTR, ">>", "link ack error\n");

                    //判断错误码，重新启动登录
                    pro_para.protool_status = 1;

                }
            }
            break;
        }

        default: break;
    }

    return 0;
}

int mof_protocol::send_up_data(unsigned char *optdata, unsigned char *data, PACKAGE_TYPE type, int isack, int optlen, int len, U8 checks)
{
    time_t curtime;
    time(&curtime);
    long opt = opt_time;
    long cur = curtime;

    if(cur - opt == 0)
    {
        qDebug() << "send_up delay";
    }

    opt_time = curtime;

    PACKAGE_HEAD pk_head;
    DATA_HEAD dt_head;

    memset(&pk_head, 0, sizeof(pk_head));
    memset(&dt_head, 0, sizeof(dt_head));

    dt_head.optLength = optlen;

    if((len == 0)&&(optlen == 0))
        return -1;

    isack =isack&0x7;

    pk_head.magic = DX_MAGIC_HEAD;
    pk_head.headp = (type|(isack<<5));

    //printf("===%x\n",pk_head.headp);
    dt_head.checksum = checks;
    dt_head.length = len;


    char senddata[1024];
    memset(senddata, 0, 1024);
    memcpy(senddata, &pk_head, PACKAGE_HEAD_LENGTH);
    memcpy(senddata + PACKAGE_HEAD_LENGTH, &dt_head, DATA_HEAD_LENGTH);
    if((optlen)&&(optdata))
        memcpy(senddata + PACKAGE_HEAD_LENGTH + DATA_HEAD_LENGTH, optdata, optlen);
    if((len)&&(data))
        memcpy(senddata + PACKAGE_HEAD_LENGTH + DATA_HEAD_LENGTH + optlen, &data[0], len);

    QByteArray tmp = QByteArray(senddata, len + PACKAGE_HEAD_LENGTH + DATA_HEAD_LENGTH + optlen);

    QString tsr = QString::number(tmp.length());
    emit mofSignalLog(CommSignalSlot::logSTR, "sendData:", tsr);

    TcpClient::Intance()->sendData(tmp);

    return 0;
}

int mof_protocol::send_business_up_data(void *buff, int len)
{
    int datalen;
    if(!pro_para.link_status)
        return -1;
    if((len>1022)||(len<=0))
        return -1;

    char  decdata[1024];
    char miwen_hex[1024];
    char checkkdata[1024];

    int milen = 0;

    memset(decdata, 0, 1024);
    memset(miwen_hex, 0, 1024);
    memset(checkkdata, 0, 1024);

    memcpy(&decdata[PACKAGE_SEQ_LENGTH],buff, len);
    datalen = PACKAGE_SEQ_LENGTH + len;
    int ret = aes_encrypt((char*)pro_para.conf.protool_key, decdata, miwen_hex, datalen, &milen);
    if(ret !=0)
        return ret;

    short midatalen = milen;
    //midatalen = midatalen;
    memcpy(checkkdata, &midatalen, PACKAGE_DATA_LENGTH);
    memcpy(checkkdata + PACKAGE_DATA_LENGTH, decdata, datalen);

    U8 checks = get_check_sum((unsigned char*)checkkdata,PACKAGE_DATA_LENGTH + datalen);

    return send_up_data((unsigned char*)0,
                        (unsigned char*)miwen_hex,
                        bissness_pack_up,
                        ACK_YES,
                        0,
                        milen,
                        checks);

}

int mof_protocol::send_management_up_data(void *buff, int len)
{
    int datalen;
    if(!pro_para.link_status)
        return -1;
    if((len>1022)||(len<=0))
        return -1;

    data_device_mo_req *p_dev_msg = (data_device_mo_req *)buff;

    char  decdata[1024];
    char miwen_hex[1024];
    char checkkdata[1024];

    int milen = 0;

    memset(decdata, 0, 1024);
    memset(miwen_hex, 0, 1024);
    memset(checkkdata, 0, 1024);


    memcpy(&decdata[PACKAGE_SEQ_LENGTH], &p_dev_msg->dataType, 1);
    U16 tmp = p_dev_msg->length;
    memcpy(&decdata[PACKAGE_SEQ_LENGTH + 1],&tmp,2);
    memcpy(&decdata[PACKAGE_SEQ_LENGTH + 3],p_dev_msg->dataByte, p_dev_msg->length);
    datalen = PACKAGE_SEQ_LENGTH + 3 + p_dev_msg->length;

    p_dev_msg->length = p_dev_msg->length;

    int ret = aes_encrypt((char*)pro_para.conf.protool_key,decdata,miwen_hex,datalen,&milen);
    if(ret != 0)
        return ret;

    short midatalen = milen;
    midatalen = midatalen;
    memcpy(checkkdata,&midatalen, PACKAGE_DATA_LENGTH);
    memcpy(checkkdata + PACKAGE_DATA_LENGTH, decdata, datalen);

    U8 checks = get_check_sum((unsigned char*)checkkdata, PACKAGE_DATA_LENGTH + datalen);

    return send_up_data((unsigned char*)0,
                        (unsigned char*)miwen_hex,
                        management_pack_up,
                        ACK_YES,
                        0,
                        milen,
                        checks);

}

int mof_protocol::send_business_ack_data(short errcode, unsigned char *buff, int len)
{
    int datalen = 0;
    if(!pro_para.link_status)
        return -1;
    if(len>1022)
        return -1;

    char optdata[2];
    errcode = errcode;
    memcpy(optdata, &errcode, 2);

    if(len>0)
    {
        char decdata[1024];
        char miwen_hex[1024];
        char checkkdata[1024];
        int milen = 0;

        memset(decdata, 0, 1024);
        memset(miwen_hex, 0, 1024);
        memset(checkkdata, 0, 1024);

        memcpy(&decdata[PACKAGE_SEQ_LENGTH],buff,len);
        datalen = len;
        int ret = aes_encrypt((char*)pro_para.conf.protool_key, decdata, miwen_hex, datalen, &milen);
        if(ret != 0)
            return ret;

        short midatalen = milen;
        //midatalen = midatalen;
        memcpy(checkkdata, &midatalen, PACKAGE_DATA_LENGTH);
        memcpy(checkkdata + PACKAGE_DATA_LENGTH, optdata, 2);
        memcpy(checkkdata + PACKAGE_DATA_LENGTH + 2, decdata, datalen);

        U8 checks = get_check_sum((unsigned char*)checkkdata, PACKAGE_DATA_LENGTH + 2 + datalen);

        return send_up_data((unsigned char*)optdata,
                            (unsigned char*)miwen_hex,
                            bissness_pack_ack,
                            ACK_NO,
                            2,
                            milen,
                            checks);
    }
    else
    {
        int dlen = 0;
        char checkkdata[1024];
        memset(checkkdata, 0, 1024);

        short datalen = dlen;
        datalen = datalen;
        memset(checkkdata, 0, 1024);
        memcpy(checkkdata, &datalen, PACKAGE_DATA_LENGTH);
        memcpy(checkkdata + PACKAGE_DATA_LENGTH, optdata, 2);


        U8 checks = get_check_sum((unsigned char*)checkkdata, PACKAGE_DATA_LENGTH + 2);
        return send_up_data((unsigned char*)optdata,
                            (unsigned char*)0,
                            bissness_pack_ack,
                            ACK_NO,
                            2,
                            0,
                            checks);
    }
}

int mof_protocol::send_management_ack_data(short errcode, unsigned char *buff, int len)
{
    if(!pro_para.link_status)
        return -1;
    if(len > 1022)
        return -1;
    char optdata[2];
    //errcode = swapInt16(errcode);
    memcpy(optdata, &errcode, 2);

    if(len > 0)
    {
        char decdata[1024];
        char miwen_hex[1024];
        char checkkdata[1024];
        int milen = 0;

        memset(decdata, 0, 1024);
        memset(miwen_hex, 0, 1024);
        memset(checkkdata, 0, 1024);

        memcpy(&decdata[PACKAGE_SEQ_LENGTH], buff, len);

        int datalen = PACKAGE_SEQ_LENGTH + len;

        int ret = aes_encrypt((char*)pro_para.conf.protool_key, decdata, miwen_hex, datalen, &milen);
        if(ret != 0)
            return ret;

        short midatalen = milen;
        memcpy(checkkdata, &midatalen, PACKAGE_DATA_LENGTH);
        memcpy(checkkdata + PACKAGE_DATA_LENGTH, optdata, 2);
        memcpy(checkkdata + PACKAGE_DATA_LENGTH + 2, decdata, datalen);

        u8 checks = get_check_sum((unsigned char*)checkkdata, PACKAGE_DATA_LENGTH + 2 + datalen);

        return send_up_data((unsigned char*)optdata,
                            (unsigned char*)miwen_hex,
                            management_pack_ack,
                            ACK_NO,
                            2,
                            milen,
                            checks);
    }
    else
    {
        int dlen = 0;
        char  checkkdata[1024];
        memset(checkkdata, 0, 1024);

        short datalen = dlen;
        //datalen = swapInt16(datalen);
        memcpy(checkkdata, &datalen, PACKAGE_DATA_LENGTH);
        memcpy(checkkdata + PACKAGE_DATA_LENGTH, optdata, 2);

        u8 checks = get_check_sum((unsigned char*)checkkdata, PACKAGE_DATA_LENGTH + 2);

        return send_up_data((unsigned char*)optdata,
                            (unsigned char*)0,
                            management_pack_ack,
                            ACK_NO,
                            2,
                            dlen,
                            checks);
    }
}

/// -------------设备---------------
// *设备数据下行*

// data：数据内容json字符串
// data_len：数据长度
///-- 备注：在不需要应答的情况下，response只需要回复下行数据中的sequence内容即可 --

// 举例：
//     下行数据data内容为：{"sequence":65535,"SongControlS":2}
//     应答数据response内容为：{"sequence":65535,"xxx1":"",......}，其中应答内容出了sequence外，根据具体情景可以包含多个参数
//     ---其中应答数据中的sequence为下行数据中的sequence的值
int mof_protocol::dev_data_down(const char *data, int data_len)
{
    #define SEQUENCE_STR ("\"sequence\":")

    //printf("######## data=%s len=%d \n", data, data_len);
    //printf("######## %s OK. \n", __func__);
    int ret = -1;

    if(NULL == data)
    {
        return ret;
    }

    char *str = strstr(data, SEQUENCE_STR);
    if(str) {
        char seq[10] = {0};
        int i = 0;
        str += strlen(SEQUENCE_STR);
        while(*str) {
            if(*str >= '0' && *str <= '9') {
                seq[i++] = *str;
            }
            else {
                break;
            }
            str++;
        }
        char seq1[24];
        snprintf(seq1, 24, "{%s%s}", SEQUENCE_STR, seq);
        emit mofSignalLog(CommSignalSlot::logSTR, ">>cmd ack:", seq1);

        send_business_ack_data(0, (u8 *)seq1, strlen(seq1));
    }

}

U16 get_dev_sn(char *sn){
    //获取SN号的功能厂商自己实现，本函数仅供参考

//    char sndata[128] = "123455432112338";
    char sndata[128] = "123455432112339";
    memcpy(&sn[0], sndata, strlen(sndata));
    return 0;
};

int mof_protocol::login_service()
{
    char optdata[LOGIN_OPT_LENGTH + 1]; // 可选部数据
    char decdata[1024];       // 待加密数据
    int datalen = 0;          // 数据部长度
    char miwen_hex[1024];     // 加密后数据
    int milen = 0;            // 加密后数据长度
    U8 checkkdata[1024];      // 校验和数据内容

    U8 deviceSnLength = 0;    // sn长度

    memset(optdata, 0, LOGIN_OPT_LENGTH + 1);
    memset(decdata, 0, 1024);
    memset(miwen_hex, 0, 1024);
    memset(checkkdata, 0, 1024);

    /// 判断pinc和key
    if (strlen (pro_para.conf.pin_code) == 0){
        printf("!\n!\n!\n!\n########ERROR: PIN is empty, plese check your plug.conf!\n!\n!\n!\n");
        return 0;
    }
    if (strlen (pro_para.conf.protool_key) == 0)
    {
        printf("!\n!\n!\n!\n########ERROR: KEY is empty, plese check your plug.conf!\n!\n!\n!\n");
        return 0;
    }

    /// 获取sn
    //if(0 != get_dev_sn(pro_para.conf.sn_code)){
    //   printf("!\n!\n!\n!\n########ERROR: SN is empty!\n!\n!\n!\n");
    //    return 0;
    //};
    // 赋值sn长度
    deviceSnLength = strlen(pro_para.conf.sn_code);

    /// 获取mac
    U8 mac[6] = {0xFC, 0xEE, 0xE6, 0x63, 0xE5, 0x0A};

    /// ------- 可选部 --------
    optdata[0] = 2;
    memcpy(&optdata[3], pro_para.conf.pin_code, strlen(pro_para.conf.pin_code));


    /// ------- 待加密数据 --------
    // 前两个字节是包序号seq
    // 赋值pincode
    memcpy(&decdata[PACKAGE_SEQ_LENGTH], pro_para.conf.pin_code, strlen(pro_para.conf.pin_code));
    // 赋值sn长度
    decdata[PACKAGE_SEQ_LENGTH + 12] = deviceSnLength;
    // 赋值sn
    memcpy(&decdata[PACKAGE_SEQ_LENGTH + 12 + 1], pro_para.conf.sn_code, deviceSnLength);
    // 赋值mac
    memcpy(&decdata[PACKAGE_SEQ_LENGTH + 13 + deviceSnLength], mac, 6);
    // 计算数据部长度，包头 + pincode + sn长度 + sn + mac + deviceID
    datalen = PACKAGE_SEQ_LENGTH + 13 + deviceSnLength + 6 + 32;

    int ret = aes_encrypt((char*)pro_para.conf.protool_key, decdata, miwen_hex, datalen, &milen);
    if(ret != 0) return ret;
    //printf("aes_crypt_ecb encode: ----len %d---\n",dlen);

    QByteArray sA = QByteArray(decdata, datalen);
    QString log = QUIHelper::byteArrayToHexStr(sA);
    emit mofSignalLog(CommSignalSlot::logSTR, "decData:", log);

    sA = QByteArray(miwen_hex, milen);
    log = QUIHelper::byteArrayToHexStr(sA);
    emit mofSignalLog(CommSignalSlot::logSTR, "encData:", log);

    /// ------- 校验和 --------
    short midatalen = milen;
    //midatalen = swapInt16(midatalen);
    memcpy(checkkdata, &midatalen, PACKAGE_DATA_LENGTH);
    memcpy(checkkdata + PACKAGE_DATA_LENGTH, optdata, LOGIN_OPT_LENGTH);
    memcpy(checkkdata + PACKAGE_DATA_LENGTH + LOGIN_OPT_LENGTH, decdata, datalen);

    U8 checksum = get_check_sum((unsigned char *) checkkdata, PACKAGE_DATA_LENGTH + LOGIN_OPT_LENGTH + datalen);

    return send_up_data((unsigned char *) optdata,
                        (unsigned char *) miwen_hex,
                        login_conform,
                        ACK_YES,
                        LOGIN_OPT_LENGTH,
                        midatalen,
                        checksum);

}

int mof_protocol::heart_beep()
{
    if(!TcpClient::Intance()->isTcpConnect()) return 0;

    data_heartbeat_opt optdata = {0};
    time_t curtime;
    time(&curtime);
//    optdata.timestamp = swapInt32(curtime);
    optdata.timestamp = 0x5ECF0001;
    U8 checks = get_check_sum((unsigned char*)&optdata,sizeof(optdata));

    int ret = send_up_data((unsigned char *)&optdata,
                           (unsigned char *) 0,
                           heart,
                           ACK_YES,
                           sizeof(optdata),
                           0,
                           checks);
    return ret;
}

//发送固件版本信息
int mof_protocol::dev_version_report()
{
    char ver[32] = {0};

    memcpy(ver, "{\"version\":\"V1.00\"}", strlen("{\"version\":\"V1.00\"}"));

    data_device_mt_req report_msg;
    report_msg.dataType = datatype_version_report;

    report_msg.dataByte = (u8 *)ver;
    report_msg.length = strlen(ver);

    //printf("######## %s %d: len = [%d] pJson = \n%s\n\n", __func__, __LINE__, report_msg.length, report_msg.dataByte);

    send_management_up_data((void *)&report_msg, sizeof(report_msg)+report_msg.length);


    return 0;
}

void mof_protocol::run()
{
    static quint8 flag = 0, linkok = 0, lflag = 0;
    static int heartTick = 0;

    if((!pro_para.login_status) && (!pro_para.protool_status) && linkok == 0)
    {
        if(flag == 5) login_service();

        if(++flag >= 60) {
            flag = 0;
        }
        linkok = 0;
        lflag = 0;
        return;
    }

    if(!pro_para.protool_status)
    {
        time_t curtime;
        time(&curtime);
        long updateTime = curtime;

        //此处对心跳ack监测
        if((pro_para.heart_time != 0)&&(updateTime - pro_para.heart_time) > pro_para.heart_interval*3)
        {
            pro_para.protool_status = 1;
            printf("heart beep error\n");
        }
    }

    if(flag > 0) {
        flag = 0;
        TcpClient::Intance()->tcpClientStop();
        TcpClient::Intance()->tcpSlotStart(pro_para.link_server, pro_para.link_port);
        linkok = 1;
    }

    if(linkok == 1 && TcpClient::Intance()->isTcpConnect()) {
        linkok = 2;
    }

    if(linkok == 2) {
        if(pro_para.link_status == 0) {
            if(lflag == 0) link_service();

            if(++lflag >= 60) {
                lflag = 0;
            }
        }
        else {
            linkok = 3;
        }
    }

    if(linkok == 3) {
        linkok = 4;
        heart_beep();
        dev_version_report();
        heartTick = 0;
    }

    if(!pro_para.protool_status)
    {
        if(++heartTick >= pro_para.heart_interval) {
            heartTick = 0;
            heart_beep();
        }
    }
}

int mof_protocol::link_service()
{
#define VERSION_0   1
#define VERSION_1   0
#define VERSION_2   3
#define VERSION_3   2

    data_link_opt optdata;    // 可选部
    data_link data;           // 数据部的包数据
    char decdata[1024];       // 待加密数据
    int datalen = 0;          // 数据部长度
    char miwen_hex[1024];     // 加密后数据
    int milen = 0;            // 加密后数据长度
    U8 checkkdata[1024];      // 校验和数据内容

    memset(&data, 0, sizeof(data));
    memset(decdata, 0, 1024);
    memset(miwen_hex, 0, 1024);
    memset(checkkdata, 0, 1024);

    if((!pro_para.login_status)&&(!pro_para.link_status))
        return -1;

    memset(optdata.devicePin, 0, sizeof(optdata.devicePin));
    memcpy(optdata.devicePin, pro_para.conf.pin_code, 12);

    memset(optdata.token, 0, sizeof(optdata.token));
    memcpy(optdata.token, pro_para.link_tocken, 32);

    /// ------- 数据部 --------
    data.protocol = 0;
    data.deviceVersion[0] = VERSION_0;
    data.deviceVersion[1] = VERSION_1;
    data.deviceVersion[2] = VERSION_2;
    data.deviceVersion[3] = VERSION_3;

    // 计算数据部长度
    datalen = PACKAGE_SEQ_LENGTH + sizeof(data_link);

    /// ------- 待加密数据 --------
    memcpy(&decdata[2], &data, sizeof(data_link));
    int ret = aes_encrypt((char*)pro_para.conf.protool_key, decdata, miwen_hex, datalen, &milen);
    if(ret !=0)
        return ret;

    /// ------- 校验和 --------
    short midatalen = milen;
    //midatalen = swapInt16(midatalen);
    memcpy(checkkdata, &midatalen, PACKAGE_DATA_LENGTH);
    memcpy(checkkdata + PACKAGE_DATA_LENGTH, &optdata, sizeof(optdata));
    memcpy(checkkdata + PACKAGE_DATA_LENGTH + sizeof(optdata), &decdata, datalen);

    U8 checks = get_check_sum((unsigned char *) checkkdata, PACKAGE_DATA_LENGTH + sizeof(data_link_opt) + datalen);

    return send_up_data((unsigned char *) &optdata,
                        (unsigned char *) miwen_hex,
                        link_conform,
                        ACK_YES,
                        sizeof(optdata),
                        milen,
                        checks);

}

void mof_protocol::mof_pharse()
{
    char buffer[256];
    PACKAGE_HEAD phead;
    DATA_HEAD dhead;
    char  optbuff[128];
    short seq;
    if(popup(&phead, &dhead, optbuff, buffer, &seq) == 0)
    {
        if((phead.headp&0x1f)==11) {
            QString tmp = QString("login_status or connnect ack len = %1,%2").arg(dhead.length).arg(dhead.optLength);
            emit mofSignalLog(CommSignalSlot::logSTR, ">>", tmp);
        }
        mof_recv_parse(phead, dhead, optbuff, buffer, seq);
    }
}

void mof_protocol::upData()
{
    const char* up = "{\"GasState\":0,\"relay1\":0,\"DateTime\":\"20201130 10:31:13\",\"CH4\":0,\"errCode\":6,\"rssi\":20,\"AlarmSound\":0,\"relay2\":0}";

    send_business_up_data((void *)up, strlen(up));
}
